package com.googlecode.afx.view.behavior.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.googlecode.afx.utils.AFXUtils;
import com.googlecode.afx.view.NodeWrapper;
import com.googlecode.afx.view.View;
import com.googlecode.afx.view.behavior.ChangeDetails;
import com.googlecode.afx.view.behavior.ViewBehavior;
import com.googlecode.afx.view.behavior.ViewStateListener;
import com.googlecode.afx.view.behavior.ViewStateManager;

import javafx.beans.value.ChangeListener;
import javafx.scene.Node;

/**
 * Straight-forward implementation of the <tt>ViewStateManager</tt> interface.
 * 
 * @author Martin
 *
 */
public class ViewStateManagerImpl implements ViewStateManager, ViewStateListener {

	private static final Log LOG = LogFactory.getLog(ViewStateManagerImpl.class);
	
	private View view;
	
	private List<ViewBehavior> viewBehaviors = new ArrayList<ViewBehavior>();
	
	public ViewStateManagerImpl(View view) {
		if(view == null) {
			throw new IllegalArgumentException("Constructor argument 'view' must not be null!");
		}
		this.view = view;
		this.view.addListener(this);
	}

	@Override
	public void onStateChange(Node rootNode, ChangeDetails changeDetails) {
		LOG.debug("View state of view with id='" + view.getId() + "' changed.");
		if(this.viewBehaviors != null && this.viewBehaviors.size() > 0) {
			for(ViewBehavior behavior : this.viewBehaviors) {
				behavior.evaluateAndApply(rootNode);
			}
		}
	}	
	
	@Override
	public ViewStateManager enable(String nodeId) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		node.setDisable(false);
		return this;
	}

	@Override
	public ViewStateManager disable(String nodeId) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		node.setDisable(true);
		return this;
	}

	@Override
	public ViewStateManager hide(String nodeId) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		node.setVisible(false);
		return this;
	}

	@Override
	public ViewStateManager show(String nodeId) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		node.setVisible(true);
		return this;
	}

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void install(String nodeId, ChangeListener listener) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		NodeWrapper wrapper = new NodeWrapper(node);
		wrapper.getPrimaryObservableValue().addListener(listener);
	}

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public void install(String nodeId, String propertyMethodName, ChangeListener listener) {
		Node node = AFXUtils.findNodeById(view.getNode(), nodeId);
		this.throwIllegalArgumentIfNull(nodeId, node);
		NodeWrapper wrapper = new NodeWrapper(node);
		wrapper.getObservableValue(propertyMethodName).addListener(listener);
	}
	
	
	/** 
	 * Throws an <tt>IllegalArgumentException</tt> in case <tt>resolvedNove</tt> is <tt>null</tt>.
	 * @param nodeId
	 * @param resolvedNode
	 */
	private void throwIllegalArgumentIfNull(String nodeId, Node resolvedNode) {
		if(resolvedNode == null) {
			LOG.warn("Node with id='" + nodeId + "' can not be found in view with id='" + view.getId() + "'! Is it a typo?");
			throw new IllegalArgumentException("Node with id='" + nodeId + "' can not be found in view with id='" + view.getId() + "'! Is it a typo?");
		}
	}
	
	/**
	 * Adds a defined <tt>ViewBehavior</tt> to this <tt>ViewStateManager</tt>.
	 * 
	 * @param viewBehavior
	 */
	public void addViewBehavior(ViewBehavior viewBehavior) {
		if(viewBehavior == null) {
			throw new IllegalArgumentException("Argument 'viewBehavior' must not be null!");
		}
		this.viewBehaviors.add(viewBehavior);
	}

}
